#pragma once
#include "NuiApi.h"
#include <string>
using namespace std;

class KinectLib;

struct KinectImageFrame
{
    // BBGGRRAA, 32 bits
    int     width;
    int     height;
    int     stride;
    int     bytes; // =height*stride
    byte *  bits;
};

struct KinectDepthFrame
{
    int                     width;
    int                     height;
    int                     minDepth;
    int                     maxDepth;
    NUI_DEPTH_IMAGE_PIXEL * depths; // count = width*height
};

struct SkeletonPoint
{
    int x;
    int y;
    int depth;
    SkeletonPoint() { x = y = depth = 0; }
};

// class IKinectCallback
class IKinectCallback
{
public:
    IKinectCallback() { }
    virtual ~IKinectCallback() { }

public:
    virtual void onKinectColorFrame(KinectLib *pKinect, const KinectImageFrame &frame) = 0;
    virtual void onKinectDepthFrame(KinectLib *pKinect, const KinectDepthFrame &frame) = 0;
    virtual void onKinectSkeletonFrame(KinectLib *pKinect, const NUI_SKELETON_FRAME &frame) = 0;
};

// class KinectLib
class KinectLib
{
public:
    KinectLib();
    virtual ~KinectLib();

public:
    void    setCallback(IKinectCallback *pCallback);
    // open first kinect sensor
    HRESULT open(bool enableColor, bool enableDepth, bool enableSkeleton);
    void    close();

    // for debugging
    void    setRecordSkeletonFile(const char *skeleonFile);
    void    startRecordSkeleton();
    void    stopRecordSkeleton();
    bool    isRecordSkeletonStarted();

    void    setReplaySkeletonFile(const char *skeleonFile);
    void    setReplaySkeletonDelay(int delayMS = 30);
    int     getReplaySkeletonDelay();
    bool    startReplaySkeleton();
    bool    isReplaySkeletoStarted();
    void    stopReplaySkeleton();
    void    pauseOrResumeReplaySkeleton();
    bool    isReplaySkeletonPaused();

public:
    static SkeletonPoint convertSkeletonPosition(const Vector4 &position, int width, int height);
    static bool checkSkeletonTracked(const NUI_SKELETON_FRAME &frame);

private:
    struct ThreadContext
    {
        KinectLib *pKinect;
        int        id;
    };
    static DWORD WINAPI _ThreadProc(LPVOID lpParam);
    DWORD onThreadProc(int id);

    HANDLE startThread(int id);
    void   stopThreads();

private:
    IKinectCallback *   mCallback;

    INuiSensor *        mNuiSensor;

    bool                mColorEnabled;
    HANDLE              mColorEvent;
    HANDLE              mColorHandle;
    HANDLE              mColorThread;
    SIZE                mColorImageSize;

    bool                mDepthEnabled;
    HANDLE              mDepthEvent;
    HANDLE              mDepthHandle;
    HANDLE              mDepthThread;
    SIZE                mDepthImageSize;

    bool                mSkeletonEnabled;
    HANDLE              mSkeletonEvent;
    HANDLE              mSkeletonThread;

    bool                mIsStop;

    // for debugging
    string              mRecordSkeletonFile;
    bool                mIsRecordSkeleton;

    string              mReplaySkeletonFile;
    FILE *              mFileReplaySkeleton;
    bool                mIsReplaySkeleton;
    bool                mIsReplayPaused;
    int                 mReplayDelayMS;
    HANDLE              mReplaySkeletonThread; // id : 1001
};